﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Web;
using OpenRasta.IO;
using OpenRasta.Web;
using uREST.CMS.Extensions;
using uREST.CMS.MediaFactories;
using uREST.Core.Attributes;
using uREST.Core.Extensions;
using uREST.Core.Handlers;
using umbraco.cms.businesslogic.media;

namespace uREST.CMS.Handlers
{
    [UmbracoAuthorize(Applications = "media")]
    public class MediaHandler : AbstractHandler
    {
        public MediaHandler(ICommunicationContext context)
            : base(context)
        { }

        // GET (LIST)
        [HttpOperation(ForUriName = "MediaList")]
        public OperationResult GetMediaList(
            [Optional, DefaultParameterValue(-1)] int parentId,
            [Optional] string mediaTypeAlias)
        {
            var mediaList = new List<Media>();

            if (parentId <= 0)
                parentId = Math.Max(-1, AuthenticatedUser.StartMediaId);

            if (parentId > 0)
            {
                Media parentMedia = null;

                try
                {
                    parentMedia = new Media(parentId);
                }
                catch { }

                if (parentMedia == null)
                    return new OperationResult.BadRequest();

                if (!AuthenticatedUser.CanAccess(parentMedia))
                    return new OperationResult.Forbidden();

                try
                {
                    if (parentMedia.HasChildren)
                        mediaList.AddRange(parentMedia.Children);
                }
                catch
                { }
            }
            else
            {
                mediaList.AddRange(Media.GetRootMedias());
            }

            if (!string.IsNullOrEmpty(mediaTypeAlias))
                mediaList = mediaList.Where(doc => doc.ContentType.Alias == mediaTypeAlias).ToList();

            return new OperationResult.OK { ResponseResource = mediaList.ToResourceList() };
        }

        // GET (SINGLE)
        [HttpOperation(ForUriName = "Media")]
        public OperationResult GetMedia(
            int id)
        {
            Media media = null;

            try
            {
                media = new Media(id);
            }
            catch
            { }

            if (media == null)
                return new OperationResult.NotFound();

            if (!AuthenticatedUser.CanAccess(media))
                return new OperationResult.Forbidden();

            return new OperationResult.OK { ResponseResource = media.ToResource() };
        }

        // CREATE
        [HttpOperation(ForUriName = "MediaList")]
        public OperationResult PostMedia(
            [Optional, DefaultParameterValue(-1)]int parentId,
            [Optional]Resources.Media resource,
            [Optional]IFile file)
        {
            if ((resource == null && file == null) || (resource != null && resource.Id > 0))
                return new OperationResult.BadRequest();

            // Check permissions on parent node
            parentId = parentId == -1 && resource != null && resource.ParentId > 0 ?
                resource.ParentId :
                parentId == -1 ? Math.Max(-1, AuthenticatedUser.StartMediaId) : parentId;

            Media parentMedia = null;

            try
            {
                parentMedia = new Media(parentId);
            }
            catch
            { }

            if (parentMedia == null)
                return new OperationResult.NotFound();

            if (!AuthenticatedUser.CanAccess(parentMedia))
                return new OperationResult.Forbidden();

            // Validate media name
            var mediaName = "";

            if (resource != null && !string.IsNullOrEmpty(resource.Name))
                mediaName = resource.Name;
            else if (file != null)
                mediaName = file.FileName;

            if (string.IsNullOrEmpty(mediaName))
                return new OperationResult.BadRequest();

            Media media = null;

            umbraco.cms.businesslogic.media.MediaType mediaType = resource != null && !string.IsNullOrEmpty(resource.MediaTypeAlias) ?
                umbraco.cms.businesslogic.media.MediaType.GetByAlias(resource.MediaTypeAlias) :
                null;

            // If we have a mediaType, create the media item first
            if (mediaType != null)
            {
                media = Media.MakeNew(mediaName, mediaType, AuthenticatedUser, parentId);
            }

            if (file != null)
            {
                var uploadedFile = new UploadedFile(file);

                // If there is no media item, create it from the file
                if (media == null)
                {
                    // Create media from file
                    var factory = MediaFactory.GetMediaFactoryCreator(parentId, uploadedFile, AuthenticatedUser);
                    if (factory == null)
                        return new OperationResult.NotFound();

                    media = factory.CreateMedia(parentId, uploadedFile, AuthenticatedUser);
                }
                else
                {
                    // If there is a media item, update the previously created media item
                    var factory = MediaFactory.GetMediaFactoryUpdater(media.Id, uploadedFile, AuthenticatedUser);
                    if (factory == null)
                        return new OperationResult.NotFound();

                    media = factory.UpdateMedia(media.Id, uploadedFile, AuthenticatedUser);
                }
            }

            // If we haven't created a media item by now, something went wrong
            if (media == null)
                return new OperationResult.BadRequest();

            // Update any passed in properties
            if (resource != null)
            {
                if (!string.IsNullOrEmpty(resource.Name))
                    media.Text = resource.Name;

                if (resource.Properties != null && resource.Properties.Count > 0)
                {
                    foreach (var propResource in resource.Properties)
                    {
                        var prop = media.getProperty(propResource.Key);
                        if (prop != null)
                            prop.Value = propResource.Value;
                    }
                }

                media.Save();
            }

            return new OperationResult.Created { ResponseResource = media.ToResource() };
        }

        // UPDATE (RESOURCE)
        [HttpOperation(ForUriName = "Media")]
        public OperationResult PutMedia(int id, 
            [Optional]Resources.Media resource,
            [Optional]IFile file)
        {
            if (resource == null && file == null)
                return new OperationResult.BadRequest();

            Media media = null;

            try
            {
                media = new Media(id);
            }
            catch
            { }

            if (media == null)
                return new OperationResult.NotFound();

            if (!AuthenticatedUser.CanAccess(media))
                return new OperationResult.Forbidden();

            if(file != null)
            {
                var uploadedFile = new UploadedFile(file);

                var factory = MediaFactory.GetMediaFactoryUpdater(id, uploadedFile, AuthenticatedUser);
                if (factory == null)
                    return new OperationResult.NotFound();

                media = factory.UpdateMedia(id, uploadedFile, AuthenticatedUser);  
            }

            if(resource != null)
            {
                if (resource.ParentId > 0)
                {
                    Media parentMedia = null;

                    try
                    {
                        parentMedia = new Media(resource.ParentId);
                    }
                    catch
                    { }

                    if (parentMedia == null)
                        return new OperationResult.NotFound();

                    if (!AuthenticatedUser.CanAccess(parentMedia))
                        return new OperationResult.Forbidden();

                    media.Move(resource.ParentId);
                }

                if (!string.IsNullOrEmpty(resource.Name))
                    media.Text = resource.Name;

                if (resource.Properties != null && resource.Properties.Count > 0)
                {
                    foreach (var propResource in resource.Properties)
                    {
                        var prop = media.getProperty(propResource.Key);
                        if (prop != null)
                            prop.Value = propResource.Value;
                    }
                }

                media.Save();
            }

            return new OperationResult.Created { ResponseResource = media.ToResource() };
        }

        // DELETE
        [HttpOperation(ForUriName = "Media")]
        public OperationResult DeleteMedia(
            int id,
            [Optional, DefaultParameterValue(false)] bool permanent)
        {
            Media media = null;

            try
            {
                media = new Media(id);
            }
            catch
            { }

            if (media == null)
                return new OperationResult.NotFound();

            if (!AuthenticatedUser.CanAccess(media))
                return new OperationResult.Forbidden();

            try
            {
                media.delete(permanent);
                return new OperationResult.NoContent();
            }
            catch
            {
                return new OperationResult.InternalServerError();
            }
        }
    }
}
